﻿using System;
using System.Collections.Data;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;

// The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235

namespace HDK.UI.Controls
{
    [TemplatePart(Name = "PART_Breadcrumb", Type = typeof(ItemsControl))]
    [TemplatePart(Name = "PART_FiltersGrid", Type = typeof(Grid))]
    [TemplatePart(Name = "PART_FilterButton", Type = typeof(Button))]
    
    public sealed class AdvancedSemanticZoom : Control
    {
        #region Breadcrumb and FilterList item templates
        public DataTemplate BreadcrumbItemTemplate
        {
            get { return (DataTemplate)GetValue(BreadcrumbItemTemplateProperty); }
            set { SetValue(BreadcrumbItemTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BreadcrumbItemTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BreadcrumbItemTemplateProperty =
            DependencyProperty.Register("BreadcrumbItemTemplate", typeof(DataTemplate), typeof(AdvancedSemanticZoom), new PropertyMetadata(null));

        public DataTemplate FilterListItemTemplate
        {
            get { return (DataTemplate)GetValue(FilterListItemTemplateProperty); }
            set { SetValue(FilterListItemTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BreadcrumbItemTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FilterListItemTemplateProperty =
            DependencyProperty.Register("FilterListItemTemplate", typeof(DataTemplate), typeof(AdvancedSemanticZoom), new PropertyMetadata(null));
        #endregion

        #region RootFilter and FilterStack and Subfilters
        public IDataFilterer RootFilter
        {
            get { return (IDataFilterer)GetValue(RootFilterProperty); }
            set { SetValue(RootFilterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RootFilter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RootFilterProperty =
            DependencyProperty.Register("RootFilter", typeof(object), typeof(AdvancedSemanticZoom), new PropertyMetadata(null, new PropertyChangedCallback(OnRootFilterValueChanged)));

        private static void OnRootFilterValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            AdvancedSemanticZoom self = d as AdvancedSemanticZoom;
            var newValue = e.NewValue as IDataFilterer;
            self.PushFilter(newValue);
        }

        public ObservableCollection<IDataFilterer> FilterStack
        {
            get
            {
                return (ObservableCollection<IDataFilterer>)GetValue(FilterStackProperty);
            }
            set
            {
                SetValue(FilterStackProperty, value);
            }
        }
        // Using a DependencyProperty as the backing store for FilterStack.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FilterStackProperty =
            DependencyProperty.Register("FilterStack", typeof(ObservableCollection<IDataFilterer>), typeof(AdvancedSemanticZoom), new PropertyMetadata(new ObservableCollection<IDataFilterer>(), new PropertyChangedCallback(OnFilterStackValueChanged)));

        private static void OnFilterStackValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            AdvancedSemanticZoom self = d as AdvancedSemanticZoom;
            self.UpdateSubFilters();
        }

        public IEnumerable<object> SubFilters
        {
            get
            {
                return (IEnumerable<object>)GetValue(SubFiltersProperty);
            }
            set
            {
                SetValue(SubFiltersProperty, value);
            }
        }
        // Using a DependencyProperty as the backing store for FilterStack.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SubFiltersProperty =
            DependencyProperty.Register("SubFilters", typeof(IEnumerable<object>), typeof(AdvancedSemanticZoom), new PropertyMetadata(null));

        #endregion

        private ItemsControl m_Breadcrumb;
        private DelegateCommand<IDataFilterer> m_ApplyFilterCommand;


        public AdvancedSemanticZoom()
        {
            this.DefaultStyleKey = typeof(AdvancedSemanticZoom);
            
            m_ApplyFilterCommand =
                    new DelegateCommand<IDataFilterer>((lastSelectedFilter) =>
                    {
                        PushOrPopToFilter(lastSelectedFilter);
                        UpdateSubFilters();
                        //UpdateBookFilters();
                    });

        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            m_Breadcrumb = GetTemplateChild("PART_Breadcrumb") as ItemsControl;
            
            var but = GetTemplateChild("PART_FilterButton") as Button;

            ReassignFilterCommands();
        }



        public void UpdateSubFilters()
        {
            IDataFilterer topFilter = this.PeekFilter();
            if (topFilter != null)
            {
                if (topFilter.HasSubFilters)
                {
                    // return a collection of subfilters
                    topFilter.RefreshSubFilters();
                    SubFilters = topFilter.SubFilters.AsEnumerable();
                    //NotifyPropertyChanged("SubFilters");
                }
                else
                {
                    // return the book results
                    topFilter.RefreshResults();
                    SubFilters = null;
                    //NotifyPropertyChanged("SubFilters");


                    //DisplayResults = topFilter.Results;
                    //NotifyPropertyChanged("DisplayResults");
                }
            }
            ReassignFilterCommands();
        }



        /// <summary>
        /// A collection that we can bind to that represents the results that should
        /// be displayed in the LibraryNavigation area.
        /// </summary>
        //public IEnumerable<object> SubFilters { get; private set; }

        private void UpdateFilters()
        {
            IDataFilterer last = this.PeekFilter();
            if (last == null) return;
            last.RefreshResults();
            if (last.Results == null) return;
        }

        public void PushFilter(IDataFilterer filter)
        {
            IDataFilterer last = this.PeekFilter();
            if (last != null)
            {
                last.IsLastInStack = false;
            }

            FilterStack.Add(filter);

            filter.IsLastInStack = true;
            //NotifyPropertyChanged("FilterStack");

            UpdateSubFilters();
            UpdateFilters();
        }

        public IDataFilterer PeekFilter()
        {
            if (FilterStack.Count > 0) return FilterStack.Last();
            return null;
        }

        public IDataFilterer PopFilter()
        {
            IDataFilterer filter = FilterStack.Last();

            if (FilterStack.Count > 1)
            {
                FilterStack.RemoveAt(FilterStack.Count - 1);
                //NotifyPropertyChanged("FilterStack");
                UpdateSubFilters();
                UpdateFilters();
            }

            return filter;
        }

        /// <summary>
        /// Pops filters off the stack until the provided filter is on top of the stack 
        /// or the stack is empty (and just the default filter remains)
        /// </summary>
        public IDataFilterer PopToFilter(IDataFilterer filter)
        {
            while (FilterStack.Count > 0)
            {
                if (FilterStack.Last() == filter)
                {
                    return filter;
                }
                else
                {
                    PopFilter();
                }
            }

            if (FilterStack.Count > 0)
            {
                return FilterStack.Last();
            }
            return null;
        }

        /// <summary>
        /// If the provided filter is already in the stack, then we pop to it. Else, if it is a valid
        /// subfilter of the top of the stack then we push it. Otherwise, we do nothing.
        /// </summary>
        public void PushOrPopToFilter(IDataFilterer filter)
        {
            // check to see if its already in our history
            if (FilterStack.Contains(filter))
            {
                PopToFilter(filter);
                return;
            }

            //FilteredHubItemFilter last = this.PeekFilter() as FilteredHubItemFilter;
            //if (last != null && last.SubFilters.Contains(filter))
            //{
            //    PushFilter(filter);
            //}
        }
        private void ReassignFilterCommands()
        {
            var buttons = this.GetChildObjects<Button>();
            foreach (var b in buttons)
                b.Command = m_ApplyFilterCommand;
        }

        private void ClickHandler(object sender, RoutedEventArgs e)
        {
            // The 'sender' is the button that raised the event.  Great!
            // Now how do I figure out the class (MyViewModel) instance that goes with this button?
        }

    }
}
